package com.imdroid.carac;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;

// 用法：
//	Tts.speak( "张三 距离 " );
//	Tts.speakDistance( 1234.5678 );
//	Tts.speak( " 到 目地地址" );

public class Tts {




private static StringBuilder sb = new StringBuilder();

static {
	new Thread( new Runnable() { public void run() {
		threadRun();
	} } ).start();
}

public static void init() {
}

private static void threadRun() { try {
	Map<Character,String> char2pinyin = new HashMap<Character,String>();
	{
	BufferedReader in = new BufferedReader( new InputStreamReader( IMDroid.getContext().getResources().openRawResource( R.raw.char2pinyin ) ) );
	while( true ) {
		String s = in.readLine();
		if( s == null )
			break;
		s = s.trim();
		if( s.equals("") )
			continue;
		char c = s.charAt(0);
		s = s.substring(1);
		char2pinyin.put( c, s );
	}
	in.close();
	}

	Map<String,int[]> pinyin2pcm = new HashMap<String,int[]>();
	{
	BufferedReader in = new BufferedReader( new InputStreamReader( IMDroid.getContext().getResources().openRawResource( R.raw.pinyin2pcm ) ) );
	while( true ) {
		String s = in.readLine();
		if( s == null )
			break;
		s = s.trim();
		if( s.equals("") )
			continue;
		String[] ss = s.split(" ");
		pinyin2pcm.put( ss[0], new int[] { Integer.parseInt(ss[1]), Integer.parseInt(ss[2]) } );
	}
	in.close();
	}

	byte[] pinyinPcm = new byte[4194954]; // res/raw/pinyin_pcm file length
	{
	InputStream in = IMDroid.getContext().getResources().openRawResource( R.raw.pinyin_pcm );
	in.read( pinyinPcm );
	in.close();
	}

	AudioTrack audio = new AudioTrack(
		AudioManager.STREAM_SYSTEM,
		8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT,
		AudioTrack.getMinBufferSize( 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT ),
		AudioTrack.MODE_STREAM );
	audio.play();

	while( true ) {
		String s = null;
		synchronized( Tts.class ) {
			if( sb.length() == 0 ) {
				try {
					Tts.class.wait();
				} catch (InterruptedException e) {
					throw new RuntimeException( e );
				}
				continue;
			}
			s = sb.toString();
			sb.delete( 0, sb.length() );
		}
		
		StringBuilder sbt = new StringBuilder();
		for( char c : s.toCharArray() ) {
			if( "，。？！,.?!".indexOf(c) != -1 ) // 长停顿=两个短停顿
				sbt.append( "__" );
			else if( " 、".indexOf(c) != -1 ) // 短停顿
				sbt.append( "_" );
			else
				sbt.append( c );
		}
		s = sbt.toString();
		
		for( char c : s.toCharArray() ) {
			String pinyin = char2pinyin.get( c );
			if( pinyin == null )
				pinyin = ""+c;
			
			int[] offLen = pinyin2pcm.get( pinyin );
			if( offLen == null ) // 没有发音数据的字符都当作短停顿
				offLen = pinyin2pcm.get( "_" );
			int off = offLen[0];
			int len = offLen[1];
//int e = 0;
//for( int i = off; i < off+len; i ++ )
//	e += pinyinPcm[i] * pinyinPcm[i];
//Log.e("C",String.format( "%s off=%s len=%s e=%s%n", pinyin, off, len, e ));
			
			audio.write( pinyinPcm, off, len );
		}
	}
} catch (IOException e) { throw new RuntimeException( e ); } }

// 字符串中空格和下划线都表示一个短停顿 0.25 秒
public static synchronized void speak( String sentence ) {
	sb.append( sentence );
	Tts.class.notifyAll();
}

// 距离单位为米，朗读时取三位有效数字，例如：一百二十三米，一点二三公里
public static void speakDistance( double distance ) {
	speak( parseDistance( distance ) );
}

private static char[] cnNumber = "零一二三四五六七八九".toCharArray();
private static String parsePositiveInt( String string ) {
	StringBuilder result = new StringBuilder();
	
	for( int group = (string.length()-1)/4; group>=0; group -- ) { // 4位一组（万）分割，从右往左数第几组，0开始
		int p = string.length() - 1 - group * 4 - 4;
		
		boolean zero = false; // 中文读法的间隔零
		if( ++p>=0) {
			char c = cnNumber[string.charAt( p )-'0'];
			if( c=='零' )
				zero = true;
			else
				result.append( c ).append( '千' );
		}
		
		if( ++p>=0) {
			char c = cnNumber[string.charAt( p )-'0'];
			if( c=='零' )
				zero = true;
			else
				result.append( zero ? "零" : "" ).append( c ).append( '百' );
		}
		
		if( ++p>=0) {
			char c = cnNumber[string.charAt( p )-'0'];
			if( c=='零' )
				zero = true;
			else
				result.append( zero ? "零" : "" ).append( c ).append( '十' );
		}

		if( ++p>=0) {
			char c = cnNumber[string.charAt( p )-'0'];
			if( c=='零' )
				;
			else
				result.append( zero ? "零" : "" ).append( c );
		}
		
		if( group % 2 == 1 )
			result.append( "万" );
		for( int k = 0; k < group/2; k ++ )
			result.append( "亿" );
	}
	return result.toString();
}

static String parseDistance( double v ) {
	StringBuilder result = new StringBuilder();
	String s = String.format( "%f", v );
	
	if( s.startsWith( "-" ) )
		result.append( "负" );
	s = s.replaceAll( "-", "" );

	// 小数点位置
	int p = s.indexOf( '.' );
	s = s.replaceAll( "\\.", "" );
	String unit = "米";
	if( p > 3 ) {
		p -= 3;
		unit = "公里";
	}
	
	char[] a = s.toCharArray();
	for( int i = 3; i < a.length; i ++ ) // 保留三位有效数字
		a[i] = '0';
	
	result.append( parsePositiveInt(new String( a, 0, p )) ); // 整数部分
	
	String floatPart = new String( a, p, a.length-p );
	while( floatPart.endsWith("0") )
		floatPart = floatPart.substring(0,floatPart.length()-1);
	if( ! floatPart.isEmpty() ) {
		result.append( '点' );
		for( char c : floatPart.toCharArray() )
			result.append( cnNumber[c-'0'] );
	}
	
	return result.append(unit).toString();
}





}
